#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Excel数据匹配工具
功能：匹配工资表和钉钉考勤表中的工资标准数据
作者：AI Assistant
"""

import sys
import os
import pandas as pd
import tkinter as tk
from tkinter import ttk, filedialog, messagebox
from pathlib import Path
import threading
from typing import Optional, Dict, List

class ExcelMatcher:
    """Excel数据匹配核心类"""
    
    def __init__(self):
        self.salary_file_path: Optional[str] = None
        self.ding_folder_path: Optional[str] = None
        self.salary_df: Optional[pd.DataFrame] = None
        self.ding_df: Optional[pd.DataFrame] = None
        self.result_df: Optional[pd.DataFrame] = None
        
    def load_salary_file(self, file_path: str) -> bool:
        """加载工资表文件"""
        try:
            self.salary_file_path = file_path
            self.salary_df = pd.read_excel(file_path)
            return True
        except Exception as e:
            print(f"加载工资表文件失败: {e}")
            return False
    
    def load_ding_folder(self, folder_path: str) -> bool:
        """加载ding文件夹中的Excel文件"""
        try:
            self.ding_folder_path = folder_path
            excel_files = []
            
            # 查找文件夹中的所有Excel文件
            for file in Path(folder_path).glob("*.xlsx"):
                if not file.name.startswith('~$'):  # 排除临时文件
                    excel_files.append(file)
            
            if not excel_files:
                print("ding文件夹中没有找到Excel文件")
                return False
            
            # 合并所有Excel文件
            all_data = []
            for file_path in excel_files:
                try:
                    # 钉钉Excel文件的标题行在第2、3行，使用skiprows=2跳过前两行
                    df = pd.read_excel(file_path, skiprows=2)
                    
                    # 清理列名，去除空白字符
                    df.columns = [str(col).strip() if pd.notna(col) else col for col in df.columns]
                    
                    # 删除完全为空的行
                    df = df.dropna(how='all')
                    
                    all_data.append(df)
                    print(f"成功读取文件: {file_path}，列名: {list(df.columns)[:5]}...")
                except Exception as e:
                    print(f"读取文件失败 {file_path}: {e}")
            
            if all_data:
                self.ding_df = pd.concat(all_data, ignore_index=True)
                print(f"成功合并 {len(all_data)} 个文件，共 {len(self.ding_df)} 行数据")
                return True
            else:
                return False
            
        except Exception as e:
            print(f"加载ding文件夹失败: {e}")
            return False
    
    def match_data(self, progress_callback=None) -> bool:
        """执行数据匹配"""
        try:
            if self.salary_df is None or self.ding_df is None:
                return False
            
            # 复制工资表数据
            self.result_df = self.salary_df.copy()
            
            # 初始化新列
            self.result_df['钉钉中的工资标准'] = ''
            self.result_df['是否匹配'] = ''
            
            # 获取姓名列（假设都叫"姓名"）
            if '姓名' not in self.salary_df.columns:
                print("工资表中没有找到'姓名'列")
                return False
            
            # 查找姓名列（钉钉表中姓名列通常是第3列，包含具体人名）
            possible_name_columns = ['姓名', '姓名（必填）', '员工姓名', '名字', '图片']
            ding_name_column = None
            
            # 首先尝试预定义的列名
            for col in possible_name_columns:
                if col in self.ding_df.columns:
                    ding_name_column = col
                    break
            
            # 如果找不到预定义的姓名列，智能识别姓名列
            if ding_name_column is None:
                # 智能识别姓名列：优先检查第2列、第3列、第4列
                candidate_columns = []
                if len(self.ding_df.columns) >= 2:
                    candidate_columns.append((1, self.ding_df.columns[1]))  # 第2列（索引1）
                if len(self.ding_df.columns) >= 3:
                    candidate_columns.append((2, self.ding_df.columns[2]))  # 第3列（索引2）
                if len(self.ding_df.columns) >= 4:
                    candidate_columns.append((3, self.ding_df.columns[3]))  # 第4列（索引3）
                
                for col_index, col_name in candidate_columns:
                    sample_data = self.ding_df[col_name].dropna().head(10)
                    if len(sample_data) > 0:
                        # 检查是否包含2-4个中文字符的姓名
                         chinese_names = []
                         job_titles = ['秩序员', '礼宾员', '队长', '领班', '保安', '门岗']
                         
                         for val in sample_data:
                             val_str = str(val).strip()
                             # 检查是否是2-4个中文字符（典型的中文姓名）
                             if 2 <= len(val_str) <= 4 and all('\u4e00' <= char <= '\u9fff' for char in val_str):
                                 # 排除职位名称，只保留真正的人名
                                 if val_str not in job_titles:
                                     chinese_names.append(val_str)
                         
                         # 如果找到至少2个中文姓名，认为是姓名列
                         if len(chinese_names) >= 2:
                             ding_name_column = col_name
                             print(f"智能识别到姓名列（第{col_index+1}列）：{ding_name_column}，样本姓名: {chinese_names[:3]}")
                             break
                
                if ding_name_column is None:
                    print(f"钉钉表中没有找到合适的姓名列")
                    print(f"实际列名：{list(self.ding_df.columns)}")
                    return False
            
            print(f"找到姓名列：{ding_name_column}")
            
            # 查找工资标准列（可能的列名）
            salary_columns = ['工资标准', '基本工资', '工资', '薪资标准', '各项扣款']
            ding_salary_col = None
            salary_salary_col = None
            
            # 在钉钉表中查找工资标准列
            for col in salary_columns:
                if col in self.ding_df.columns:
                    # 检查该列是否包含数字数据（工资金额）
                    sample_data = self.ding_df[col].dropna().head(10)
                    if len(sample_data) > 0:
                        numeric_count = 0
                        for val in sample_data:
                            try:
                                num_val = float(val)
                                if 1000 <= num_val <= 50000:  # 合理的工资范围
                                    numeric_count += 1
                            except:
                                pass
                        
                        # 如果至少30%的数据是合理的工资数字，则认为是工资列
                        if numeric_count >= len(sample_data) * 0.3:
                            ding_salary_col = col
                            print(f"找到钉钉表工资标准列: {ding_salary_col}")
                            break
            
            # 如果还没找到，尝试智能识别包含工资数据的列
            if ding_salary_col is None:
                print("未找到预定义工资标准列，开始智能识别...")
                for col in self.ding_df.columns:
                    try:
                        sample_data = self.ding_df[col].dropna().head(10)
                        if len(sample_data) > 0:
                            numeric_count = 0
                            salary_values = []
                            for val in sample_data:
                                try:
                                    num_val = float(val)
                                    if 1000 <= num_val <= 50000:  # 合理的工资范围
                                        numeric_count += 1
                                        salary_values.append(num_val)
                                except:
                                    pass
                            
                            # 如果至少30%的数据是合理的工资数字
                            if numeric_count >= len(sample_data) * 0.3 and len(salary_values) >= 2:
                                ding_salary_col = col
                                print(f"智能识别到工资标准列：{ding_salary_col}，样本工资: {salary_values[:3]}")
                                break
                    except:
                        continue
            
            # 在工资表中查找工资标准列
            for col in salary_columns:
                if col in self.salary_df.columns:
                    salary_salary_col = col
                    break
            
            if ding_salary_col is None:
                print(f"钉钉表中没有找到工资标准相关列")
                print(f"钉钉表可用列名: {list(self.ding_df.columns)}")
                return False
            
            print(f"找到钉钉表工资标准列: {ding_salary_col}")
            
            # 执行匹配
            total_rows = len(self.result_df)
            for index, row in self.result_df.iterrows():
                name = row['姓名']
                
                # 在钉钉表中查找匹配的姓名
                ding_match = self.ding_df[self.ding_df[ding_name_column] == name]
                
                if not ding_match.empty:
                    # 找到匹配的姓名，获取工资标准
                    ding_salary = ding_match.iloc[0][ding_salary_col]
                    self.result_df.at[index, '钉钉中的工资标准'] = ding_salary
                    
                    # 比较工资标准
                    if salary_salary_col and pd.notna(row[salary_salary_col]):
                        if str(ding_salary) == str(row[salary_salary_col]):
                            self.result_df.at[index, '是否匹配'] = '匹配'
                        else:
                            self.result_df.at[index, '是否匹配'] = '不匹配'
                    else:
                        self.result_df.at[index, '是否匹配'] = '无法比较'
                else:
                    self.result_df.at[index, '钉钉中的工资标准'] = '未找到'
                    self.result_df.at[index, '是否匹配'] = '未找到'
                
                # 更新进度
                if progress_callback:
                    progress = (index + 1) / total_rows * 100
                    progress_callback(progress)
            
            return True
            
        except Exception as e:
            print(f"数据匹配失败: {e}")
            return False
    
    def save_result(self, output_path: str) -> bool:
        """保存结果文件"""
        try:
            if self.result_df is None:
                return False
            
            self.result_df.to_excel(output_path, index=False)
            return True
            
        except Exception as e:
            print(f"保存结果失败: {e}")
            return False

class ExcelMatcherGUI:
    """GUI界面类"""
    
    def __init__(self):
        self.root = tk.Tk()
        self.matcher = ExcelMatcher()
        self.setup_ui()
        
    def setup_ui(self):
        """设置用户界面"""
        self.root.title("Excel数据匹配工具")
        self.root.geometry("800x600")
        self.root.configure(bg='#f0f0f0')
        
        # 主框架
        main_frame = ttk.Frame(self.root, padding="20")
        main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
        
        # 标题
        title_label = ttk.Label(main_frame, text="Excel数据匹配工具", 
                               font=('微软雅黑', 18, 'bold'))
        title_label.grid(row=0, column=0, columnspan=3, pady=(0, 20))
        
        # 文件选择区域
        file_frame = ttk.LabelFrame(main_frame, text="文件选择", padding="10")
        file_frame.grid(row=1, column=0, columnspan=3, sticky=(tk.W, tk.E), pady=(0, 10))
        
        # 工资表文件选择
        ttk.Label(file_frame, text="工资表文件:").grid(row=0, column=0, sticky=tk.W, pady=5)
        self.salary_file_var = tk.StringVar()
        ttk.Entry(file_frame, textvariable=self.salary_file_var, width=50).grid(row=0, column=1, padx=5)
        ttk.Button(file_frame, text="浏览", command=self.select_salary_file).grid(row=0, column=2)
        
        # ding文件夹选择
        ttk.Label(file_frame, text="ding文件夹:").grid(row=1, column=0, sticky=tk.W, pady=5)
        self.ding_folder_var = tk.StringVar()
        ttk.Entry(file_frame, textvariable=self.ding_folder_var, width=50).grid(row=1, column=1, padx=5)
        ttk.Button(file_frame, text="浏览", command=self.select_ding_folder).grid(row=1, column=2)
        
        # 操作按钮
        button_frame = ttk.Frame(main_frame)
        button_frame.grid(row=2, column=0, columnspan=3, pady=20)
        
        self.process_button = ttk.Button(button_frame, text="开始处理", 
                                        command=self.start_processing,
                                        style='Accent.TButton')
        self.process_button.pack(side=tk.LEFT, padx=5)
        
        ttk.Button(button_frame, text="保存结果", 
                  command=self.save_result).pack(side=tk.LEFT, padx=5)
        
        # 进度条
        self.progress_var = tk.DoubleVar()
        self.progress_bar = ttk.Progressbar(main_frame, variable=self.progress_var, 
                                          maximum=100, length=400)
        self.progress_bar.grid(row=3, column=0, columnspan=3, pady=10, sticky=(tk.W, tk.E))
        
        # 状态标签
        self.status_var = tk.StringVar(value="请选择文件开始处理")
        self.status_label = ttk.Label(main_frame, textvariable=self.status_var)
        self.status_label.grid(row=4, column=0, columnspan=3, pady=5)
        
        # 结果预览区域
        preview_frame = ttk.LabelFrame(main_frame, text="结果预览", padding="10")
        preview_frame.grid(row=5, column=0, columnspan=3, sticky=(tk.W, tk.E, tk.N, tk.S), pady=10)
        
        # 创建Treeview用于显示数据
        self.tree = ttk.Treeview(preview_frame, height=10)
        self.tree.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
        
        # 滚动条
        scrollbar = ttk.Scrollbar(preview_frame, orient=tk.VERTICAL, command=self.tree.yview)
        scrollbar.grid(row=0, column=1, sticky=(tk.N, tk.S))
        self.tree.configure(yscrollcommand=scrollbar.set)
        
        # 配置网格权重
        self.root.columnconfigure(0, weight=1)
        self.root.rowconfigure(0, weight=1)
        main_frame.columnconfigure(1, weight=1)
        main_frame.rowconfigure(5, weight=1)
        preview_frame.columnconfigure(0, weight=1)
        preview_frame.rowconfigure(0, weight=1)
        
    def select_salary_file(self):
        """选择工资表文件"""
        file_path = filedialog.askopenfilename(
            title="选择工资表文件",
            filetypes=[("Excel文件", "*.xlsx *.xls")]
        )
        if file_path:
            self.salary_file_var.set(file_path)
            
    def select_ding_folder(self):
        """选择ding文件夹"""
        folder_path = filedialog.askdirectory(title="选择ding文件夹")
        if folder_path:
            self.ding_folder_var.set(folder_path)
            
    def update_progress(self, value):
        """更新进度条"""
        self.progress_var.set(value)
        self.root.update_idletasks()
        
    def start_processing(self):
        """开始处理数据"""
        salary_file = self.salary_file_var.get()
        ding_folder = self.ding_folder_var.get()
        
        if not salary_file or not ding_folder:
            messagebox.showerror("错误", "请选择工资表文件和ding文件夹")
            return
        
        # 在新线程中处理数据
        def process_data():
            try:
                self.process_button.configure(state='disabled')
                self.status_var.set("正在加载文件...")
                
                # 加载文件
                if not self.matcher.load_salary_file(salary_file):
                    messagebox.showerror("错误", "加载工资表文件失败")
                    return
                
                if not self.matcher.load_ding_folder(ding_folder):
                    messagebox.showerror("错误", "加载ding文件夹失败")
                    return
                
                self.status_var.set("正在匹配数据...")
                
                # 匹配数据
                if self.matcher.match_data(self.update_progress):
                    self.status_var.set("数据匹配完成")
                    self.update_preview()
                    messagebox.showinfo("成功", "数据匹配完成！")
                else:
                    messagebox.showerror("错误", "数据匹配失败")
                    
            except Exception as e:
                messagebox.showerror("错误", f"处理过程中发生错误: {e}")
            finally:
                self.process_button.configure(state='normal')
                
        threading.Thread(target=process_data, daemon=True).start()
        
    def update_preview(self):
        """更新结果预览"""
        if self.matcher.result_df is None:
            return
        
        # 清空现有数据
        for item in self.tree.get_children():
            self.tree.delete(item)
        
        # 设置列
        columns = list(self.matcher.result_df.columns)
        self.tree['columns'] = columns
        self.tree['show'] = 'headings'
        
        # 设置列标题
        for col in columns:
            self.tree.heading(col, text=col)
            self.tree.column(col, width=100)
        
        # 插入数据（只显示前100行）
        for index, row in self.matcher.result_df.head(100).iterrows():
            values = [str(row[col]) for col in columns]
            self.tree.insert('', 'end', values=values)
            
    def save_result(self):
        """保存结果"""
        if self.matcher.result_df is None:
            messagebox.showerror("错误", "没有可保存的结果")
            return
        
        file_path = filedialog.asksaveasfilename(
            title="保存结果文件",
            defaultextension=".xlsx",
            filetypes=[("Excel文件", "*.xlsx")]
        )
        
        if file_path:
            if self.matcher.save_result(file_path):
                messagebox.showinfo("成功", f"结果已保存到: {file_path}")
            else:
                messagebox.showerror("错误", "保存文件失败")
                
    def run(self):
        """运行应用程序"""
        self.root.mainloop()

def main():
    """主函数"""
    try:
        app = ExcelMatcherGUI()
        app.run()
    except Exception as e:
        print(f"程序启动失败: {e}")
        messagebox.showerror("错误", f"程序启动失败: {e}")

if __name__ == "__main__":
    main()
